package com.scenic.rd_android.testview.lstview;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.text.format.Formatter;
import android.util.LruCache;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;

import com.nova.scenic.projectlibs.util.debug.MyLog;
import com.scenic.rd_android.R;

import java.lang.ref.WeakReference;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * 原文地址: http://blog.csdn.net/guolin_blog/article/details/45586553
 * 使用互相持有弱引用 来解决图片错位
 *
 * @author guolin
 */
public class ImageAdapterWeekReference extends ArrayAdapter<String> {


    private static final String TAG = "ImageAdapterWeekReference";
    private final Bitmap mLoadingBitmap;
    /**
     * 图片缓存技术的核心类，用于缓存所有下载好的图片，在程序内存达到设定值时会将最少最近使用的图片移除掉。
     */
    private LruCache<String, BitmapDrawable> mMemoryCache;

    public ImageAdapterWeekReference(Context context, int resource, String[] objects) {
        super(context, resource, objects);
        mLoadingBitmap = BitmapFactory.decodeResource(context.getResources(),
                R.drawable.ic_chooser);
        // 获取应用程序最大可用内存
        int maxMemory = (int) Runtime.getRuntime().maxMemory();
        int cacheSize = maxMemory / 8;
        MyLog.i(TAG, "max memory is " + Formatter.formatFileSize(context,maxMemory));
        mMemoryCache = new LruCache<String, BitmapDrawable>(cacheSize) {
            @Override
            protected int sizeOf(String key, BitmapDrawable drawable) {
                return drawable.getBitmap().getByteCount();
            }
        };
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        String url = getItem(position);
        View view;
        if (convertView == null) {
            view = LayoutInflater.from(getContext()).inflate(R.layout.adapter_listview_load_image_ectopic, null);
        } else {
            view = convertView;
        }
        ImageView image = (ImageView) view.findViewById(R.id.image);

        BitmapDrawable drawable = null;//getBitmapFromMemoryCache(url);
        if (drawable != null) {
            image.setImageDrawable(drawable);
        } else if(cancelPotentialWork(url,image)) {
            BitmapWorkerTask task = new BitmapWorkerTask(image);
            AsyncDrawable asyncDrawable = new AsyncDrawable(getContext()
                    .getResources(), mLoadingBitmap, task);
            image.setImageDrawable(asyncDrawable);
            task.execute(url);
            MyLog.i(TAG,"set Task: imageView " + image + "  Task " + task);
        }
        return view;
    }

    /**
     * 取消掉后台的潜在任务，当认为当前ImageView存在着一个另外图片请求任务时
     * ，则把它取消掉并返回true，否则返回false。
     */
    public boolean cancelPotentialWork(String url, ImageView imageView) {
//        BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
        BitmapWorkerTask bitmapWorkerTask = null;

        if(imageView.getDrawable() instanceof AsyncDrawable){
            bitmapWorkerTask = ((AsyncDrawable) imageView.getDrawable()).getBitmapWorkerTask();
        }
        MyLog.i(TAG,"check cancelTask " + imageView + "===" +bitmapWorkerTask);
        if (bitmapWorkerTask != null) {
            String imageUrl = bitmapWorkerTask.imageUrl;
            if (imageUrl == null || !imageUrl.equals(url)) {
                bitmapWorkerTask.cancel(true);
            } else {
                return false;
            }
        }
        return true;
    }

    /**
     * 将一张图片存储到LruCache中。
     *
     * @param key      LruCache的键，这里传入图片的URL地址。
     * @param drawable LruCache的值，这里传入从网络上下载的BitmapDrawable对象。
     */
    public void addBitmapToMemoryCache(String key, BitmapDrawable drawable) {
        if (getBitmapFromMemoryCache(key) == null) {
            mMemoryCache.put(key, drawable);
        }
    }

    /**
     * 从LruCache中获取一张图片，如果不存在就返回null。
     *
     * @param key LruCache的键，这里传入图片的URL地址。
     * @return 对应传入键的BitmapDrawable对象，或者null。
     */
    public BitmapDrawable getBitmapFromMemoryCache(String key) {
        return mMemoryCache.get(key);
    }

    public static int BitmapWorkTaskID = 0;
    /**
     * 异步下载图片的任务。
     *
     * @author guolin
     */
    class BitmapWorkerTask extends AsyncTask<String, Void, BitmapDrawable> {

        private WeakReference<ImageView> imageViewReference;

        private int id;
        private String imageUrl;

        public BitmapWorkerTask(ImageView imageView) {
            imageViewReference = new WeakReference<>(imageView);
            id = BitmapWorkTaskID++;
        }

        @Override
        protected BitmapDrawable doInBackground(String... params) {
            imageUrl = params[0];
            // 在后台开始下载图片
            Bitmap bitmap = downloadBitmap(imageUrl);
            BitmapDrawable drawable = new BitmapDrawable(getContext().getResources(), bitmap);
            addBitmapToMemoryCache(imageUrl, drawable);
            return drawable;
        }

        @Override
        protected void onPostExecute(BitmapDrawable drawable) {
//            MyLog.i(TAG,"Task onPostExecute " + this);
            //获取当前BitmapWorkerTask所关联的ImageView。
            ImageView imageView = imageViewReference.get();

            BitmapWorkerTask bitmapWorkerTask = null;

            if (imageView != null) {
                //获取传入的ImageView它所对应的BitmapWorkerTask。

                MyLog.i(TAG,"task===ImageView reference is " +this + " == " + imageView);

                Drawable drawableOfImageView = imageView.getDrawable();
                if (drawableOfImageView instanceof AsyncDrawable) {
                    AsyncDrawable asyncDrawable = (AsyncDrawable) drawableOfImageView;
                    bitmapWorkerTask = asyncDrawable.getBitmapWorkerTask();
                    MyLog.i(TAG,"the task of image hold is " + bitmapWorkerTask);
                }
            }else {
                MyLog.i(TAG,"task===ImageView reference is " +this + " == null" );
            }

            if (this != bitmapWorkerTask) {
                MyLog.i(TAG,"current task is not imageView hold task\n\r");
                return;
            }

            if (imageView != null && drawable != null) {
                imageView.setImageDrawable(drawable);
                MyLog.i(TAG,"set image success " + imageView + " === " + this + "\n\r");

            }else {
                MyLog.w(TAG,"null " + imageView + "  " + drawable);
            }

        }

        /**
         * 建立HTTP请求，并获取Bitmap对象。
         *
         * @param imageUrl 图片的URL地址
         * @return 解析后的Bitmap对象
         */
        private Bitmap downloadBitmap(String imageUrl) {
            Bitmap bitmap = null;
            HttpURLConnection con = null;
            try {
                URL url = new URL(imageUrl);
                con = (HttpURLConnection) url.openConnection();
                con.setConnectTimeout(5 * 1000);
                con.setReadTimeout(10 * 1000);
                bitmap = BitmapFactory.decodeStream(con.getInputStream());
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (con != null) {
                    con.disconnect();
                }
            }
            return bitmap;
        }






        @Override
        public String toString() {
            return "BitmapWorkerTask id " + id;
        }
    }




    /**
     * 自定义的一个Drawable，让这个Drawable持有BitmapWorkerTask的弱引用。
     */
    public static class AsyncDrawable extends BitmapDrawable {

        private WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;

        public AsyncDrawable(Resources res, Bitmap bitmap,BitmapWorkerTask bitmapWorkerTask) {
            super(res, bitmap);
            bitmapWorkerTaskReference = new WeakReference<>(bitmapWorkerTask);
        }

        public BitmapWorkerTask getBitmapWorkerTask() {
            return bitmapWorkerTaskReference.get();
        }

    }

}
